Imports System.ComponentModel

Public Class frmPrefs
    Inherits System.Windows.Forms.Form

    Shared Project As clsProject

    'note: following classes were changed to derive from UITypeEditor rather than FileNameEditor so that the full Framework 4 is not required (will only need Client Framework)

    Private Class clsGraphicFileEditor : Inherits System.Drawing.Design.UITypeEditor

        Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return Drawing.Design.UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
            With New OpenFileDialog
                .AddExtension = True
                .CheckFileExists = True
                .DefaultExt = "bmp"
                .Filter = "All Image Files (*.bmp,*.gif,*.jpg,*.jpeg,*.png,*.ico,*.emf,*.wmf)|*.bmp;*.gif;*.jpg;*.jpeg;*.png;*.ico;*.emf;*.wmf"
                If String.IsNullOrEmpty(Project.DesktopGraphicFile) Then
                    .InitialDirectory = MyDataPath()
                Else
                    .InitialDirectory = IO.Path.GetDirectoryName(Project.DesktopGraphicFile)
                End If
                .FileName = Project.DesktopGraphicFile
                If .ShowDialog() = Windows.Forms.DialogResult.OK Then
                    Return .FileName
                Else
                    Return "" 'if cancel, will clear
                End If
            End With
        End Function
    End Class

    Private Class clsGisFileEditor : Inherits System.Drawing.Design.UITypeEditor

        Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return Drawing.Design.UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
            With New OpenFileDialog
                .AddExtension = True
                .CheckFileExists = True
                .DefaultExt = "gis"
                .Filter = "GIS Files (*.gis)|*.gis"
                If String.IsNullOrEmpty(Project.GisBasemapStations) Then
                    .InitialDirectory = MyDataPath()
                    .FileName = Project.GisBasemapStations
                Else
                    .InitialDirectory = IO.Path.GetDirectoryName(Project.GisBasemapStations)
                End If
                If .ShowDialog() = Windows.Forms.DialogResult.OK Then
                    Return .FileName
                Else
                    Return "" 'if cancel, will clear entry
                End If
            End With
        End Function
    End Class

    Private Class clsShapeFileEditor : Inherits System.Drawing.Design.UITypeEditor

        Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return Drawing.Design.UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
            With New OpenFileDialog
                .AddExtension = True
                .CheckFileExists = True
                .DefaultExt = "shp"
                .Filter = "Shape Files (*.shp)|*.shp"
                If String.IsNullOrEmpty(Project.GisClippingLayerFilename) Then
                    .InitialDirectory = MyDataPath()
                Else
                    .InitialDirectory = IO.Path.GetDirectoryName(Project.GisClippingLayerFilename)
                End If
                If .ShowDialog() = Windows.Forms.DialogResult.OK Then
                    Return .FileName
                Else
                    Return "" 'if cancel, will clear entry
                End If
            End With
        End Function
    End Class

    Private Class clsGISFolderEditor : Inherits System.Drawing.Design.UITypeEditor
        Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return Drawing.Design.UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
            With New FolderBrowserDialog
                .Description = "Select folder where GIS shape files will be saved for this project."
                .SelectedPath = Project.GisDirectory
                If .SelectedPath = "" Then .SelectedPath = My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\WRDB"
                If .ShowDialog = Windows.Forms.DialogResult.OK Then
                    Return .SelectedPath
                Else
                    Return ""
                End If
            End With
        End Function
    End Class

    Private Class clsSQLFolderEditor : Inherits System.Drawing.Design.UITypeEditor
        Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return Drawing.Design.UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
            With New FolderBrowserDialog
                .Description = "Select folder where SQL queries will be saved for this project."
                .SelectedPath = Project.SQLDir
                If .SelectedPath = "" Then .SelectedPath = My.Computer.FileSystem.SpecialDirectories.MyDocuments & "\WRDB"
                If .ShowDialog = Windows.Forms.DialogResult.OK Then
                    Return .SelectedPath
                Else
                    Return ""
                End If
            End With
        End Function
    End Class

    Private Class clsUpdateFolderEditor : Inherits System.Drawing.Design.UITypeEditor
        Public Overrides Function GetEditStyle(context As System.ComponentModel.ITypeDescriptorContext) As System.Drawing.Design.UITypeEditorEditStyle
            Return Drawing.Design.UITypeEditorEditStyle.Modal
        End Function

        Public Overrides Function EditValue(context As System.ComponentModel.ITypeDescriptorContext, provider As System.IServiceProvider, value As Object) As Object
            With New FolderBrowserDialog
                .Description = "Select network folder where WRDB updates reside; if updates are hosted on an Internet server, cancel this dialog and type the URL."
                .SelectedPath = MainWRDB.UpdateLocation
                If .ShowDialog = Windows.Forms.DialogResult.OK Then
                    Return .SelectedPath
                Else
                    Return ""
                End If
            End With
        End Function
    End Class

    Private Class clsCriteriaRegGroupEditor : Inherits StringConverter
        Public Overrides Function GetStandardValuesSupported(context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True 'display combobox
        End Function
        Public Overrides Function GetStandardValuesExclusive(context As System.ComponentModel.ITypeDescriptorContext) As Boolean
            Return True 'select only
        End Function
        Public Overrides Function GetStandardValues(context As System.ComponentModel.ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection
            Return New StandardValuesCollection(Project.DB.GetRecordList("Criteria", "RegGroup"))
        End Function
    End Class

    <DefaultProperty("Description")>
    Private Class clsProjOptions

        <DisplayName("Description"), Category("1. Settings"),
        Description("Description for project.")>
        Public Property Description() As String
            Get
                Return Project.Description
            End Get
            Set(ByVal value As String)
                Project.Description = value
            End Set
        End Property

        <Editor(GetType(clsGraphicFileEditor), GetType(System.Drawing.Design.UITypeEditor)),
        DisplayName("Desktop Graphic File"), Category("1. Settings"),
        Description("This is the name of the graphic file that will be displayed as the desktop background. Click the ... button to browse.")>
        Public Property DesktopGraphic() As String
            Get
                Return Project.DesktopGraphicFile
            End Get
            Set(ByVal value As String)
                Project.DesktopGraphicFile = value
            End Set
        End Property

        <DisplayName("Desktop Graphic Option"), Category("1. Settings"),
        Description("Specify how the image will be scaled.")>
        Public Property DesktopGraphicOption() As Project.clsProject.enumDesktopGraphicOption
            Get
                Return Project.DesktopGraphicOption
            End Get
            Set(ByVal value As Project.clsProject.enumDesktopGraphicOption)
                Project.DesktopGraphicOption = value
            End Set
        End Property

        <DisplayName("Desktop Color Scheme"), Category("1. Settings"),
        Description("This is the name of the color scheme to use for the desktop background.")>
        Public Property DesktopColorScheme() As Project.clsProject.enumDesktopColorTheme
            Get
                Return Project.DesktopColorTheme
            End Get
            Set(ByVal value As Project.clsProject.enumDesktopColorTheme)
                Project.DesktopColorTheme = value
            End Set
        End Property

        <DisplayName("Title Bar Text"), Category("1. Settings"),
        Description("Text to display on the WRDB title bar when this project is loaded. If blank, defaults to project name.")>
        Public Property TitleBarText() As String
            Get
                Return Project.TitlebarText
            End Get
            Set(ByVal value As String)
                Project.TitlebarText = value
            End Set
        End Property

        <DisplayName("Include in Scheduled Archives?"), Category("2. Archives"),
        Description("Include this project in scheduled archives? This setting is only used when automatic Project Archives are scheduled.")>
        Public Property AutoBackup() As Boolean
            Get
                Return Project.IncludeInBackup
            End Get
            Set(ByVal value As Boolean)
                Project.IncludeInBackup = value
            End Set
        End Property

        <DisplayName("Select Records Into..."), Category("3. Query Options"),
        Description("Select 'View' for very fast queries, but which result in slow subsequent operations (e.g., reports & graphs); select 'Table' to store query results in temporary table which will take longer, but make subsequent operations much faster; select 'Subquery' for experimental approach that can be used in enterprise environments similar to Views. Views not available if using database with limited permissions.")>
        Public Property QueryOptions() As clsProject.enumQueryOption
            Get
                Return Project.QueryOption
            End Get
            Set(ByVal value As clsProject.enumQueryOption)
                If value = clsProject.enumQueryOption.Subselect Then
                    WarningMsg("The Subselect query option is not supported at this time--resetting to Table.")
                    value = clsProject.enumQueryOption.Table
                End If
                Project.QueryOption = value
            End Set
        End Property

        <Editor(GetType(clsSQLFolderEditor), GetType(System.Drawing.Design.UITypeEditor)),
         DisplayName("Saved Query Folder"), Category("3. Query Options"),
        Description("This is file path where WRDB will save and load Saved Queries and the INI file containing saved calculations.")>
        Public Property SQLDir() As String
            Get
                Return RelativePath(Project.SQLDir)
            End Get
            Set(ByVal value As String)
                Project.SQLDir = AbsolutePath(value)
            End Set
        End Property

        <DisplayName("Select from Available Records"), Category("3. Query Options"),
        Description("If true, will automatically configure query forms to display only available values in the currently selected table; otherwise, will display all records from Support tables (use this for better performance when querying very large data tables).")>
        Public Property SelectAvailable() As Boolean
            Get
                Return Project.SelectAvailable
            End Get
            Set(ByVal value As Boolean)
                Project.SelectAvailable = value
            End Set
        End Property

        <DisplayName("Use Extended Data Fields"), Category("3. Query Options"),
        Description("If true, will use larger than normal field sizes for data tables. This option would only be used if data tables are substituted with views mapped to a non-WRDB data source that may contain larger than normal key fields (e.g., the Maine DEP EGAD database).")>
        Public Property ExtendedFieldSize() As Boolean
            Get
                Return Project.ExtendedFieldSize
            End Get
            Set(ByVal value As Boolean)
                Project.ExtendedFieldSize = value
                If Project.GetTableListAll.Count > 1 Then 'settings table will always have been created; if other tables exist help them with upgrade
                    If WarningMsgFmt("Changing this setting for an existing Project will not affect existing tables, only new ones. To update all tables to use the different field sizes, WRDB will now modify the schema of each table. " & IIf(Not Project.ExtendedFieldSize, "If you have data tables that are utilizing the extended field sizes, DATA WILL BE TRUNCATED.\n\nif you haven't already done so, YOU SHOULD BACK UP YOUR PROJECT BEFORE PROCEEDING!", "") & "\n\nAre you sure you want to proceed?") = DialogResult.OK Then
                        For Each tbl As String In Project.GetTableListAll
                            MainForm.WriteProgress($"Updating table {tbl}...")
                            If Not Project.DB.UpgradeTableBruteForce(tbl, Project.GetTableTemplate(tbl)) Then
                                WarningMsg($"WRDB was unable to upgrade the table {tbl}. That leaves your database in an indeterminate state. We recommend that you create a new empty project and restore all data from your latest backup.")
                                Exit For
                            End If
                        Next
                        MainForm.ProgressComplete()
                    Else
                        Project.ExtendedFieldSize = Not value
                    End If
                End If
            End Set
        End Property

        <DisplayName("Display Advanced Menus?"), Category("4. Security"),
        Description("When true, non-Supervisor users can still see many advanced menu and toolbar items. Set to false to simplify the user interface.")>
        Public Property AdvancedMenusVisible() As Boolean
            Get
                Return Project.AdvancedMenusVisible
            End Get
            Set(ByVal value As Boolean)
                Project.AdvancedMenusVisible = value
            End Set
        End Property

        <DisplayName("Read-Only Project?"), Category("4. Security"),
        Description("When true, in addition to normal restrictions, non-Supervisor users are also prevented from creating, editing, and adding to Working tables.")>
        Public Property IsReadOnly() As Boolean
            Get
                Return Project.IsReadOnly
            End Get
            Set(ByVal value As Boolean)
                Project.IsReadOnly = value
            End Set
        End Property

        <DisplayName("Allowed Users"), Category("4. Security"),
        Description("Comma-separated list of users permitted to access this project. If blank, there are no restrictions.")>
        Public Property AllowedUsers() As String
            Get
                Return Project.AllowedUsers
            End Get
            Set(ByVal value As String)
                Project.AllowedUsers = value.Trim.ToUpper
            End Set
        End Property

        <DisplayName("WQX Displayed?"), Category("5. Display"),
        Description("When true, you will also have the ability to configure EPA's WQX (Water Quality Exchange) fields contained in the PCodes Support table.")>
        Public Property WQXVisible() As Boolean
            Get
                Return Project.WQXVisible
            End Get
            Set(ByVal value As Boolean)
                Project.WQXVisible = value
            End Set
        End Property

        '<DisplayName("Prompt When Importing?"), Category("4. Display"), _
        'Description("When true, WRDB will prompt you to enter tracking information for each file or table you import.")> _
        'Public Property PromptImport() As Boolean
        '    Get
        '        Return MainWRDB.PromptImport
        '    End Get
        '    Set(ByVal value As Boolean)
        '        MainWRDB.PromptImport = value
        '    End Set
        'End Property

        <DisplayName("Prompt For Journal Descriptions?"), Category("5. Display"),
        Description("Select if and when you will be automatically prompted to enter Journal descriptions when editing table contents. If set to 'Never', you can still choose to enter descriptions for individual edits by clicking a button on the form.")>
        Public Property PromptJournal() As clsWRDB.enumJournalPrompt
            Get
                Return MainWRDB.PromptJournal
            End Get
            Set(ByVal value As clsWRDB.enumJournalPrompt)
                MainWRDB.PromptJournal = value
            End Set
        End Property

        <DisplayName("Determine record counts?"), Category("5. Display"),
        Description("If Always will determine record counts when opening tables and after each query. If using very large tables or views, set to Never to make WRDB more responsive; use Queries_Only to bypass when opening tables but display for queries.")>
        Public Property DisplayRecordCounts() As clsProject.enumDisplayRecordCount
            Get
                Return Project.DisplayRecordCount
            End Get
            Set(ByVal value As clsProject.enumDisplayRecordCount)
                Project.DisplayRecordCount = value
            End Set
        End Property

        <DisplayName("Report Heading Line 1"), Category("6. Reporting"),
        Description("Specify line one of the report heading you want to appear at the top of printed reports; this is usually the agency name.")>
        Public Property ReportHeading1() As String
            Get
                Return Project.ReportHeading1
            End Get
            Set(ByVal value As String)
                Project.ReportHeading1 = value
            End Set
        End Property

        <DisplayName("Report Heading Line 2"), Category("6. Reporting"),
        Description("Specify line two of the report heading you want to appear at the top of printed reports; this is usually the agency location.")>
        Public Property ReportHeading2() As String
            Get
                Return Project.ReportHeading2
            End Get
            Set(ByVal value As String)
                Project.ReportHeading2 = value
            End Set
        End Property

        <DisplayName("Report Scaling"), Category("6. Reporting"),
        Description("Specify the report scaling option; this determines how wide reports are scaled to fit on the printed page.")>
        Public Property ReportScaling() As clsProject.enumReportScaling
            Get
                Return Project.ReportScaling
            End Get
            Set(ByVal value As clsProject.enumReportScaling)
                Project.ReportScaling = value
            End Set
        End Property

        <DisplayName("Report Language"), Category("6. Reporting"),
        Description("Specify the report language option; this determines the language used for report headings, footers, etc.")>
        Public Property ReportLanguage() As clsProject.enumReportLanguage
            Get
                Return Project.ReportLanguage
            End Get
            Set(ByVal value As clsProject.enumReportLanguage)
                Project.ReportLanguage = value
            End Set
        End Property

        <Browsable(True), TypeConverter(GetType(clsCriteriaRegGroupEditor)),
         DisplayName("Criteria Regulatory Group"), Category("6. Reporting"),
        Description("This is default criteria regulatory group that will be used to report excursions.")>
        Public Property CriteriaRegGroup() As String
            Get
                Return Project.CriteriaRegGroup
            End Get
            Set(ByVal value As String)
                Project.CriteriaRegGroup = value
            End Set
        End Property

        <DisplayName("Automatic BDL Detection"), Category("6. Reporting"),
        Description("If true, all values which have no RCode but have Result value less than detection limit for that PCode will be assumed to be BDL values; numeric value used in statistics will be Result value.")>
        Public Property AutoBDL() As Boolean
            Get
                Return Project.AutoBDL
            End Get
            Set(ByVal value As Boolean)
                Project.AutoBDL = value
            End Set
        End Property

        '<DisplayName("Custom Report Compatibility"), Category("5. Reporting"), _
        'Description("Specify the version of SQL Server being used; you must select SQL Server 2008 to be able to run reports stored on that version server as well as Report Builder 2.0 reports saved as RDL files (which can be used to display data using any WRDB Provider type, not just SQL Server).")> _
        'Public Property ReportCompatibility() As clsProject.enumReportCompatibility
        '    Get
        '        Return Project.ReportCompatibility
        '    End Get
        '    Set(ByVal value As clsProject.enumReportCompatibility)
        '        Project.ReportCompatibility = value
        '    End Set
        'End Property

        <DisplayName("Quick PCode/CCode List Refresh?"), Category("7. GIS"),
        Description("If True, when data tables are opened the PCode (and CCode) drop-down lists are populated with all values from the Support tables; otherwise will query data table for unique values (which can take a long time for large tables).")>
        Public Property GisQuickList() As Boolean
            Get
                Return Project.GisQuickList
            End Get
            Set(ByVal value As Boolean)
                Project.GisQuickList = value
            End Set
        End Property

        <DisplayName("Quick Attribute Table?"), Category("7. GIS"),
        Description("If True, when the WRDB Stations layer is created the associated attribute table will contain only the Station ID, name, and type; otherwise will contain all data in Stations table (which can take a long time for large tables).")>
        Public Property GisQuickTable() As Boolean
            Get
                Return Project.GisQuickTable
            End Get
            Set(ByVal value As Boolean)
                Project.GisQuickTable = value
            End Set
        End Property

        <Editor(GetType(clsGISFolderEditor), GetType(System.Drawing.Design.UITypeEditor)),
        DisplayName("GIS Directory"), Category("7. GIS"),
        Description("Use the ... button to select the directory where the WRDB stations shape file will be located.  If blank, or if that directory does not contain the intended shape file, it will be recreated temporarily for each session which may be time consuming.")>
        Public Property GisDirectory() As String
            Get
                Return Project.GisDirectory
            End Get
            Set(ByVal value As String)
                Project.GisDirectory = value
            End Set
        End Property

        <Editor(GetType(clsGisFileEditor), GetType(System.Drawing.Design.UITypeEditor)),
        DisplayName("Basemap-Stations"), Category("7. GIS"),
        Description("Use the ... button to select the WRDB GIS file containing the basemap which will be automatically loaded in the WRDB GIS tool to display station locations or select stations when performing a query. If left blank no basemap is displayed.")>
        Public Property GisBasemapStations() As String
            Get
                Return Project.GisBasemapStations
            End Get
            Set(ByVal value As String)
                Project.GisBasemapStations = value
            End Set
        End Property

        <Editor(GetType(clsGisFileEditor), GetType(System.Drawing.Design.UITypeEditor)),
        DisplayName("Basemap-Output"), Category("7. GIS"),
        Description("Use the ... button to select the shape file containing the basemap which will be automatically loaded in the WRDB GIS tool to display the thematic map of selected data. If left blank no basemap is displayed.")>
        Public Property GisBasemapOutput() As String
            Get
                Return Project.GisBasemapOutput
            End Get
            Set(ByVal value As String)
                Project.GisBasemapOutput = value
            End Set
        End Property

        <DisplayName("Data Output Option"), Category("7. GIS"),
        Description("When displaying a thematic map of selected data, this determines the type of visualization that will be used.")>
        Public Property GisOutputOption() As clsProject.enumGisOutputOption
            Get
                Return Project.GisOutputOption
            End Get
            Set(ByVal value As clsProject.enumGisOutputOption)
                Project.GisOutputOption = value
            End Set
        End Property

        <Editor(GetType(clsShapeFileEditor), GetType(System.Drawing.Design.UITypeEditor)),
        DisplayName("Data Output Grid Clipping Layer File"), Category("7. GIS"),
        Description("Use the ... button to select the polygon shape file that will be used to automatically clip the grid (for example, the boundaries of a lake). This is only used when displaying a thematic map of selected data using the Grid option.")>
        Public Property GisClippingLayerFilename() As String
            Get
                Return Project.GisClippingLayerFilename
            End Get
            Set(ByVal value As String)
                Project.GisClippingLayerFilename = value
            End Set
        End Property

        <DisplayName("Data Output Grid Size"), Category("7. GIS"),
        Description("When displaying a thematic map of selected data using the Grid option, this determines the number of rows or columns across the points layer that will be created. The larger this number, the more detailed the grid (but longer processing time).")>
        Public Property GisGridSize() As Integer
            Get
                Return Project.GisOutputGridSize
            End Get
            Set(ByVal value As Integer)
                Project.GisOutputGridSize = value
            End Set
        End Property

        <DisplayName("Data Output Number of Stations"), Category("7. GIS"),
        Description("When displaying a thematic map of selected data using the Grid option, this determines the number of nearby stations that will be used to compute spatial weights. The larger this number, the more stations will be included in the computation, but the performance will be reduced.")>
        Public Property GisNumPoints() As Integer
            Get
                Return Project.GisNumPoints
            End Get
            Set(ByVal value As Integer)
                Project.GisNumPoints = value
            End Set
        End Property

    End Class

    <DefaultProperty("Description")>
    Private Class clsAppOptions

        <DisplayName("Expert Mode?"), Category("1. Display"),
        Description("When true, some messages and prompts are suppressed and placed in status bar instead.")>
        Public Property ExpertMode() As Boolean
            Get
                Return MainWRDB.ExpertMode
            End Get
            Set(ByVal value As Boolean)
                MainWRDB.ExpertMode = value
            End Set
        End Property

        <DisplayName("Grid Font"), Category("1. Display"),
        Description("Specify the font to use within data grids (browsers, reports, etc.).")>
        Public Property GridFont() As Font
            Get
                Return MainWRDB.GridFont
            End Get
            Set(ByVal value As Font)
                MainWRDB.GridFont = value
            End Set
        End Property

        <DisplayName("Display Welcome Screen on Startup?"), Category("1. Display"),
        Description("When true, the 'Welcome to WRDB' startup dialog is displayed every time you start WRDB (does not apply to WRDB run from MapWindow). This allows you to select the initial Project and table.")>
        Public Property DisplayStartup() As Boolean
            Get
                Return MainWRDB.ShowStartup
            End Get
            Set(ByVal value As Boolean)
                MainWRDB.ShowStartup = value
            End Set
        End Property

        <DisplayName("Display New Project Screen When Switching Projects?"), Category("1. Display"),
        Description("When true, the 'New Project' dialog is displayed every time you select a new project (does not apply to WRDB run from MapWindow). This displays relevant Project information and allows you to select from a set of common tasks.")>
        Public Property DisplayNewProject() As Boolean
            Get
                Return MainWRDB.ShowNewProject
            End Get
            Set(ByVal value As Boolean)
                MainWRDB.ShowNewProject = value
            End Set
        End Property

        <DisplayName("Display Getting Started Form?"), Category("1. Display"),
        Description("When true, the 'Getting Started' form is displayed every time you start WRDB. This displays helpful WRDB fundamentals for the first-time user.")>
        Public Property DisplayGettingStarted() As Boolean
            Get
                Return MainWRDB.ShowGettingStarted
            End Get
            Set(ByVal value As Boolean)
                MainWRDB.ShowGettingStarted = value
            End Set
        End Property

        <DisplayName("Default Initials for Ownership?"), Category("2. Ownership"),
        Description("Specify the default user initials to use when making Data, Tracking, and Journal table entries and identifying data record ownership; maximum of three characters and must be unique in the workgroup (defaults to login ID).")>
        Public Property UserName() As String
            Get
                Return clsApplicationSettings.UserName
            End Get
            Set(ByVal value As String)
                clsApplicationSettings.UserName = value.ToUpper
            End Set
        End Property

        <DisplayName("Auto-check for New Versions?"), Category("3. Program Updates"),
        Description("When true, every time WRDB starts the WRDB web site (or alternate location indicated below) will be checked to see if new versions of the program or data provider libraries are available; if so you will be given the chance to download and update the required files.")>
        Public Property CheckVersions() As Boolean
            Get
                Return MainWRDB.CheckUpdates
            End Get
            Set(ByVal value As Boolean)
                MainWRDB.CheckUpdates = value
            End Set
        End Property

        <Editor(GetType(clsUpdateFolderEditor), GetType(System.Drawing.Design.UITypeEditor)),
         DisplayName("Update Repository"), Category("3. Program Updates"),
        Description("This is the URL or file path where WRDB will check for new versions. By default it is 'http://www.wrdb.com/download/wrdb6/' but may be changed to a local share to speed the distribution of updates across an organization.")>
        Public Property VersionRepository() As String
            Get
                Return MainWRDB.UpdateLocation
            End Get
            Set(ByVal value As String)
                MainWRDB.UpdateLocation = value
            End Set
        End Property

        '<Editor(GetType(clsFolderEditor), GetType(System.Drawing.Design.UITypeEditor)), _
        'DisplayName("Project File Directory"), Category("2. Application Settings"), _
        'Description("This is the name of the directory where the WRDB.ini file is stored; it contains information about all active Projects. Click the ... button to browse.")> _
        'Public Property ProjectFolder() As String
        '    Get
        '        Return AppDataPath
        '    End Get
        '    Set(ByVal value As String)
        '        If WarningMsg("This will cause the current project to close and WRDB will switch to the WRDB.ini file found in the specified directory (if present). Are you sure you want to continue?") = Windows.Forms.DialogResult.Cancel Then Exit Property
        '        ProjectMustClose = True
        '        AppDataPath = value
        '        DatabaseHasChanged = True
        '    End Set
        'End Property

        <Editor(GetType(clsSQLFolderEditor), GetType(System.Drawing.Design.UITypeEditor)),
         DisplayName("RStudio Binaries Directory"), Category("4. R Scripts"),
        Description("This is file path where the binaries for the RStudio tool are found which are needed to edit R scripts (e.g., RStudio.exe).")>
        Public Property RStudioDir() As String
            Get
                Return MainWRDB.RStudioDir
            End Get
            Set(ByVal value As String)
                MainWRDB.RStudioDir = value
            End Set
        End Property

        <Editor(GetType(clsSQLFolderEditor), GetType(System.Drawing.Design.UITypeEditor)),
         DisplayName("R Binaries Directory"), Category("4. R Scripts"),
        Description("This is file path where the R binaries are found which are needed to execute R scripts (e.g., RScript.exe).")>
        Public Property RBinaryDir() As String
            Get
                Return MainWRDB.RBinaryDir
            End Get
            Set(ByVal value As String)
                MainWRDB.RBinaryDir = value
            End Set
        End Property

        <Editor(GetType(clsSQLFolderEditor), GetType(System.Drawing.Design.UITypeEditor)),
         DisplayName("R Script Directory"), Category("4. R Scripts"),
        Description("This is file path where WRDB will load R Scripts and save the results.")>
        Public Property RScriptDir() As String
            Get
                Return MainWRDB.RScriptDir
            End Get
            Set(ByVal value As String)
                MainWRDB.RScriptDir = value
            End Set
        End Property

        <DisplayName("R Data Frame Format"), Category("4. R Scripts"),
        Description("Select the format of the Selected Data.txt file that will be created to make selected data available to R scripts.")>
        Public Property RDataFrameFormat() As clsWRDB.enumRDataFrameFormat
            Get
                Return MainWRDB.RDataFrameFormat
            End Get
            Set(ByVal value As clsWRDB.enumRDataFrameFormat)
                MainWRDB.RDataFrameFormat = value
            End Set
        End Property

        <DisplayName("Current Project Workspace Name"), Category("5. Project Workspace"),
        Description("Enter the desired name for the currently selected Project Workspace.")>
        Public Property WorkspaceName() As String
            Get
                Return clsApplicationSettings.WorkspaceName
            End Get
            Set(ByVal value As String)
                clsApplicationSettings.WorkspaceName = value
            End Set
        End Property

        <ReadOnlyAttribute(True), DisplayName("Current Project Workspace Folder"), Category("5. Project Workspace"),
        Description("This is the full path to the current Project Workspace configuration file.")>
        Public ReadOnly Property WorkspaceFile() As String
            Get
                IsAppDataPathValid()
                Return IO.Path.Combine(clsApplicationSettings.AppDataPath, "WRDB6.ini")
            End Get
        End Property

    End Class

    Private ProjOptions As clsProjOptions
    Private AppOptions As clsAppOptions
    Private LastBrowseDir As String = ""
    Shared DatabaseHasChanged As Boolean = False
    Shared ProjectMustClose As Boolean = False

    Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
        If DatabaseHasChanged Then
            If TestConnection() Then
                Dim Master As String = Project.MasterTableName 'may get lost when reset project
                clsConnections.SetProjectInfo(Project)
                Project = New clsProject(Project.Name)
                Project.MasterTableName = Master
                LoadForm()
            Else
                Exit Sub
            End If
        End If
        If SaveForm() Then
            Project = Nothing
            DialogResult = Windows.Forms.DialogResult.OK
        End If
    End Sub

    Private Function SaveForm() As Boolean
        Try

            If DatabaseHasChanged Or ProjectMustClose Then
                With MainForm
                    For Each child As Form In .MdiChildren
                        child.Close()
                    Next
                End With
            End If

            If ProjectMustClose Then
                MainWRDB = New WRDB.Lib.clsWRDB
                DialogResult = Windows.Forms.DialogResult.OK
                Return True
            End If

            With Project
                If String.IsNullOrEmpty(txtDataSource.Text) Then
                    WarningMsg("You must specify a valid name for the database server or file.")
                    Return False
                End If

                'recreate table template specs in case user selected extended fields option

                .CreateTableTemplates()

                If Not TestConnection() Then Exit Function
                .MasterTableName = Me.cboMasterTable.Text

                If .MasterTableName.Trim = "" AndAlso MessageBox.Show("No Master table has been specified for this project; do you want to create a new Master table now?", "Select/Create Master Table", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) = Windows.Forms.DialogResult.OK Then
                    btnCreateMaster.PerformClick()
                End If

                If .MasterTableName.Trim = "" Then
                    WarningMsg("You must select an existing or create a new Master table before proceeding.")
                    Return False
                End If

                If .MasterTableName <> "" AndAlso Not .DB.TableViewExists(.MasterTableName) Then
                    If MessageBox.Show(String.Format("Master Table {0} was not found. Do you want to create it?", .MasterTableName), "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) = Windows.Forms.DialogResult.Yes Then
                        If HasTablePermissions(Project) Then .CreateTable(clsProject.enumTableTypes.Master)
                    End If
                End If

                .Password = txtProjectPassword.Text.Trim

                'make sure that current user is included in the list
                Dim lstUsers As New Generic.List(Of String)
                lstUsers.AddRange(Project.AllowedUsers.Split(","))
                If Project.AllowedUsers.Trim <> "" AndAlso Not lstUsers.Contains(WRDB.Project.clsApplicationSettings.UserName()) Then
                    WarningMsgFmt("The list of allowed users does not include your initials ({0}) which would prevent you from accessing this project in the future. Therefore, your name has automatically been added to the list.\n\nNote: if you ever change your initials entered on the Application Options tab as 'Default Initials for Ownership', the presence of a list of allowed users may affect your ability to access this project. You can manually edit the WRDB6.INI file to change or remove any project's 'AllowedUsers' list.", WRDB.Project.clsApplicationSettings.UserName)
                    Project.AllowedUsers &= "," & WRDB.Project.clsApplicationSettings.UserName
                End If

                .SavePreferences()
                clsConnections.SetProjectInfo(Project)
                Dim IsLoggedIn As Boolean = modWRDB.Project.IsLoggedIn
                SetProject(.Name, Not DatabaseHasChanged)
                modWRDB.Project.IsLoggedIn = IsLoggedIn
                If Not MainForm.CheckSupportTablesExist() Then Return False

                Return True

            End With
        Catch ex As DbSqlException
            WarningMsg(ex.Message)
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Function

    Private Sub LoadForm()
        ProjectMustClose = False
        With Project
            Text = "Project Preferences: " & .Name
            With cboDatabaseType
                .Items.Clear()
                'Dim AvailTypes As Generic.List(Of clsDB.enumDBType) = clsDB.EnumDataProviders()
                'note: do not include support for dbase tables because they have 10-character limitation on field names (violated by RCodes and Branches) and limitation on creation of primary key
                For dbType As clsDB.enumDBType = clsDB.enumDBType.Access To clsDB.enumDBType.SQLite
                    Dim dbTypeName As String = dbType.ToString.Replace("_", " ")
                    .Items.Add(dbTypeName)
                Next
            End With
            If .DB Is Nothing Then
                cboDatabaseType.SelectedIndex = -1
                'hide all other controls
                For Each cntl As Control In tblConfig.Controls
                    If Not cntl.Name.EndsWith("DatabaseType") Then cntl.Visible = False
                Next
                lblNotes.Visible = True
                lblNotes.Text = "Select the database type (data provider) you wish to use for this new project (the online help manual describes the merits of each data provider). Then enter the required information for the database."
            Else
                cboDatabaseType.Text = [Enum].GetName(GetType(clsDB.enumDBType), .DB.DatabaseType).Replace("_", " ")
            End If
            cboMasterTable.Text = .MasterTableName
            cboMasterTable.MaxLength = Project.dsWRDB.Tables("TRACKING").Columns("MASTER_DB_NAME").MaxLength
            ProjOptions = New clsProjOptions
            AppOptions = New clsAppOptions
            pgProjOptions.SelectedObject = ProjOptions
            pgAppOptions.SelectedObject = AppOptions
            pgProjOptions.ToolbarVisible = False
            pgAppOptions.ToolbarVisible = False
            DatabaseHasChanged = False
            If Project Is Nothing OrElse Not Project.IsLoggedIn Then
                tabMain.TabPages.Remove(tpDatabase)
                tabMain.TabPages.Remove(tpProjOptions)
                btnLogin.Visible = True
            Else
                btnLogin.Visible = False
            End If
        End With
    End Sub

    Private Sub btnTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTest.Click
        If TestConnection() Then
            MessageBox.Show(String.Format("Successfully connected to database. The database user will{0} have database privileges that allow table creation & deletion.", IIf(Project.HasTablePermissions, "", " NOT")), "Test Connection", MessageBoxButtons.OK, MessageBoxIcon.Information)
        Else
            'MessageBox.Show("Unable to connect to database.", "Test Connection", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End If
    End Sub

    Private Function TestConnection() As Boolean
        Try
            With Project
                MainForm.WriteProgress("Connecting to database...", ProgressBarStyle.Marquee)

                Dim DataSource As String = txtDataSource.Text
                Dim DatabaseName As String = txtDatabaseName.Text

                If String.IsNullOrEmpty(DataSource) Then Return False

                Dim Ext As String

                Select Case SelectedDatabaseType()
                    Case clsDB.enumDBType.Access : Ext = ".mdb"
                    Case clsDB.enumDBType.Firebird_Embedded : Ext = ".fdb"
                    Case clsDB.enumDBType.SQLite : Ext = ".sdb"
                    Case clsDB.enumDBType.SQL_Server_CE : Ext = ".sdf"
                    Case Else
                        Ext = ""
                End Select

                Select Case SelectedDatabaseType()
                    Case clsDB.enumDBType.Access, clsDB.enumDBType.Firebird_Embedded, clsDB.enumDBType.SQLite, clsDB.enumDBType.DBase, clsDB.enumDBType.SQL_Server_CE
                        DataSource = AbsolutePath(DataSource, Ext)
                    Case clsDB.enumDBType.Firebird
                        'database files will be stored on server in the root directory, and given the extension fdb
                        DatabaseName = String.Format("\{0}.fdb", DatabaseName)
                End Select

                Try
                    .DB = clsDB.GetDataProvider(SelectedDatabaseType, DataSource, DatabaseName, txtUserName.Text, txtPswd.Text, Val(txtTimeout.Text))
                    If .DB Is Nothing Then Return False
                Catch ex As DbSqlException
                    ErrorMsg("Unable to connect to database.", ex)
                    Return False
                Catch ex As Exception
                    'CE returns error if no file exists when just create connection; give it a change to create it below
                    'If .DB.DatabaseType <> clsDB.enumDBType.SQL_Server_CE Then Return False
                    Return False
                End Try

                'make sure database exists & offer to create

                If Not .DB.TestConnection Then
                    MainForm.ProgressComplete()

                    Select Case .DB.DatabaseType
                        Case clsDB.enumDBType.Access, clsDB.enumDBType.Firebird_Embedded, clsDB.enumDBType.SQLite, clsDB.enumDBType.SQL_Server_CE
                            If MessageBox.Show(String.Format("Database {0} was not found. Do you want to create it?", .DB.DataSource), "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) = Windows.Forms.DialogResult.No Then Return False
                            Select Case .DB.DatabaseType
                                Case clsDB.enumDBType.Access, clsDB.enumDBType.SQLite, clsDB.enumDBType.SQL_Server_CE
                                    If Not String.IsNullOrEmpty(txtPswd.Text) Then
                                        Dim frm As New frmLogin
                                        frm.lblInfo.Text = "Once this database file is created with the specified password, you will not be able to access the data without resupplying it. To make sure that you have entered it correctly, please reenter it again below (and then store the password in a safe place)."
                                        frm.lblPassword.Text = "Database Password:"
                                        If frm.ShowDialog(Me) = Windows.Forms.DialogResult.Cancel OrElse frm.txtPassword.Text <> txtPswd.Text Then Return False
                                        frm.Dispose()
                                    End If
                            End Select
                            If Not .DB.CreateDatabase(.DB.DataSource) Then Return False
                            txtDataSource.Text = RelativePath(.DB.DataSource) 'name may have changed

                        Case clsDB.enumDBType.DBase
                            If Not .DB.DataSource.EndsWith("\") Then .DB.DataSource &= "\"
                            If Not My.Computer.FileSystem.DirectoryExists(.DB.DataSource) Then
                                If MessageBox.Show("The directory you specified was not found. Do you want to create it?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) = Windows.Forms.DialogResult.Yes Then
                                    My.Computer.FileSystem.CreateDirectory(.DB.DataSource)
                                Else
                                    Return False
                                End If
                            End If

                        Case clsDB.enumDBType.SQL_Server, clsDB.enumDBType.MySQL
                            If .DB.LastException IsNot Nothing Then
                                Throw .DB.LastException
                            End If
                            .DB = clsDB.GetDataProvider(SelectedDatabaseType, DataSource, IIf(.DB.DatabaseType = clsDB.enumDBType.SQL_Server, "master", "mysql"), txtUserName.Text, txtPswd.Text, txtTimeout.Text)
                            If .DB Is Nothing Then Return False
                            Try
                                .DB.OpenConnection()
                            Catch ex As DbSqlException
                                WarningMsg("Unable to connect to specified data provider database. Please check all connection and security settings.", , ex)
                                Return False
                            End Try
                            Dim dt As DataTable = .DB.Connection.GetSchema("DATABASES")

                            Dim found As Boolean = False
                            For Each dr As DataRow In dt.Rows
                                If dr("Database_Name").ToString.Equals(DatabaseName, StringComparison.OrdinalIgnoreCase) Then found = True : Exit For
                            Next
                            dt.Dispose()
                            dt = Nothing

                            If Not found AndAlso MessageBox.Show(String.Format("Database {0} was not found. Do you want to create it?", Me.txtDatabaseName.Text), "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) = Windows.Forms.DialogResult.Yes Then
                                .DB.DatabaseName = .DB.GetValidObjectName(DatabaseName)
                                If Not .DB.CreateDatabase(DatabaseName) Then Return False
                                txtDatabaseName.Text = DatabaseName
                            End If

                        Case clsDB.enumDBType.Oracle
                            Try
                                If .DB.Connection Is Nothing Then Return False 'do not allow user to create database (actually schema) because they are mapped to username by DBA
                                .DB.OpenConnection()
                            Catch ex As System.TypeInitializationException
                                WarningMsg("Unable to connect to Oracle because you do not have the necessary Oracle client libraries installed (these are not automatically installed by WRDB). Please download and install these client libraries before trying to access an Oracle database (or use a different database type). Note that you must also install Oracle Database Access Components (ODAC) libraries available from www.Oracle.com (search for 'download ODAC').", , ex)
                                Return False
                            Catch ex As DbSqlException
                                WarningMsg("Unable to connect to specified data provider database. Please check all connection and security settings.", , ex)
                                Return False
                            Catch ex As Exception
                                WarningMsg("Unable to connect to specified data provider database. Please check all connection and security settings.", , .DB.LastException)
                            End Try

                        Case clsDB.enumDBType.Firebird
                            'GetSchema doesn't include any way to list databases on Firebird server; just try to connect and if error, offer to create
                            'note that dbname in Firebird is actually full path to the database file on the server; place all on root directory under WRDB
                            Try
                                .DB.OpenConnection()
                            Catch ex As DbSqlException
                                If MessageBox.Show(String.Format("Either the Firebird server couldn't be accessed or the database '{0}' was not found. Please check all connection and security settings. Do you want to attempt to create the specified database?", IO.Path.GetFileNameWithoutExtension(.DB.DatabaseName)), "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk) = Windows.Forms.DialogResult.No Then Return False
                                If Not .DB.CreateDatabase(.DB.DatabaseName) Then
                                    WarningMsg("Unable to create database on Firebird server; this probably means that you cannot connect to the server or your security settings are incorrect.\n\nNOTE: WRDB assumes that the Firebird server is configured on this computer or another database server that you have access to it through your firewall. The physical database files will be saved on the Firebird server in the root directory of the same drive where Windows is installed and given the extension .FDB.")
                                    Return False
                                End If
                            End Try
                    End Select
                End If

                .DB.Connection.Close()
                .HasTablePermissions = .DB.HasTablePermissions
            End With
            Return True

        Catch ex As DbSqlException
            WarningMsg(ex.Message & vbCr & vbCr & ex.InnerException.Message)
            Return False
        Catch ex As Exception
            ErrorMsg(, ex)
            Return False
        Finally
            MainForm.ProgressComplete()
        End Try
    End Function

    Private Sub cboDatabaseType_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboDatabaseType.SelectedIndexChanged
        tblConfig.SuspendLayout()
        Try
            With Project
                If cboDatabaseType.SelectedIndex = -1 Then Exit Sub

                'all the following may have been made invisible if creating a new project and no database type selected yet
                lblDataSource.Visible = True
                txtDataSource.Visible = True
                btnDataSource.Visible = True
                lblMasterTable.Visible = True
                cboMasterTable.Visible = True
                btnCreateMaster.Visible = True
                lblTimeout.Visible = True
                txtTimeout.Visible = True

                lblNotes.Visible = True
                btnTest.Visible = True

                If Not MainWRDB.DataProviderAvailable(SelectedDatabaseType) Then cboDatabaseType.SelectedIndex = -1

                Dim IsEmbedded As Boolean = SelectedDatabaseType() = clsDB.enumDBType.Access Or
                                            SelectedDatabaseType() = clsDB.enumDBType.Firebird_Embedded Or
                                            SelectedDatabaseType() = clsDB.enumDBType.SQLite Or
                                            SelectedDatabaseType() = clsDB.enumDBType.SQL_Server_CE

                Dim AllowsPswd As Boolean
                Select Case SelectedDatabaseType()
                    Case clsDB.enumDBType.Access, clsDB.enumDBType.Firebird, clsDB.enumDBType.MySQL, clsDB.enumDBType.Oracle, clsDB.enumDBType.SQL_Server, clsDB.enumDBType.SQLite, clsDB.enumDBType.SQL_Server_CE
                        AllowsPswd = True
                    Case Else
                        AllowsPswd = False
                End Select

                Dim AllowBrowse As Boolean = Not (SelectedDatabaseType() = clsDB.enumDBType.Firebird)
                lblNotes.Visible = True
                btnDataSource.Enabled = True

                If IsEmbedded Then
                    lblDataSource.Text = "&Database Name:" : If .DB IsNot Nothing Then txtDataSource.Text = RelativePath(.DB.DataSource)
                    lblNotes.Text = "Note: " & cboDatabaseType.Text & " tables are all stored inside a single database file." & IIf(AllowsPswd, " The Username and Password entries are optional and will normally not be used for this data provider.", "")
                Else
                    lblDataSource.Text = "&Server Name:" : If .DB IsNot Nothing Then txtDataSource.Text = .DB.DataSource
                    btnDataSource.Enabled = False
                    lblDatabaseName.Text = "&Database Name:" : If .DB IsNot Nothing Then txtDatabaseName.Text = .DB.DatabaseName
                    If SelectedDatabaseType() = clsDB.enumDBType.Oracle Then lblDatabaseName.Text = "Schema Name:"
                    If SelectedDatabaseType() = clsDB.enumDBType.Firebird Then If .DB IsNot Nothing Then txtDatabaseName.Text = IO.Path.GetFileNameWithoutExtension(.DB.DatabaseName)
                    lblNotes.Visible = True
                    Dim port As Integer = 0
                    Dim info As String = ""
                    Select Case SelectedDatabaseType()
                        Case clsDB.enumDBType.Firebird : port = 3050 : info = " The .fdb database file MUST be stored in the root directory of the server."
                        Case clsDB.enumDBType.MySQL : port = 3306
                        Case clsDB.enumDBType.Oracle : port = 1521  'info = " The owner of all tables MUST be designated as 'WRDB'."
                        Case clsDB.enumDBType.SQL_Server : port = 1433
                    End Select
                    lblNotes.Text = String.Format("Note: this provider communicates with the database server using TCP/IP port number {0} by default. You may have to configure your computer (and workgroup's) firewall to allow traffic through this port.{1}", port, info)
                End If

                'note: Oracle employs schemas, rather than databases; these are mapped to a specific username
                'for now, do not allow schemas to be created by user (must be DBA)

                lblDatabaseName.Visible = Not (IsEmbedded Or SelectedDatabaseType() = clsDB.enumDBType.DBase)
                txtDatabaseName.Visible = Not (IsEmbedded Or SelectedDatabaseType() = clsDB.enumDBType.DBase)
                btnDatabaseName.Enabled = Not (IsEmbedded Or SelectedDatabaseType() = clsDB.enumDBType.Oracle Or SelectedDatabaseType() = clsDB.enumDBType.DBase)

                If SelectedDatabaseType() = clsDB.enumDBType.SQL_Server Then
                    chkWindowsSecurity.Visible = True
                    chkWindowsSecurity.Checked = .DB Is Nothing OrElse .DB.UserName = ""
                Else
                    chkWindowsSecurity.Visible = False
                    chkWindowsSecurity.Checked = False
                    lblUserName.Visible = AllowsPswd And Not IsEmbedded
                    txtUserName.Visible = AllowsPswd And Not IsEmbedded
                    lblPswd.Visible = AllowsPswd
                    txtPswd.Visible = AllowsPswd
                End If
                If AllowsPswd And .DB IsNot Nothing Then
                    If SelectedDatabaseType() = clsDB.enumDBType.SQL_Server AndAlso String.IsNullOrEmpty(.DB.UserName) Then
                        chkWindowsSecurity.Checked = True
                    Else
                        txtUserName.Text = .DB.UserName
                        txtPswd.Text = .DB.Password
                    End If
                End If

                btnDatabaseName.Enabled = AllowBrowse

                If .DB Is Nothing Then txtTimeout.Text = 30 Else txtTimeout.Text = .DB.CommandTimeout

                If .Password = "Not Set" Then txtProjectPassword.Text = "" Else txtProjectPassword.Text = .Password
            End With
        Catch ex As Exception
            ErrorMsg(, ex)
        Finally
            tblConfig.ResumeLayout(True)
        End Try
    End Sub

    Private Sub btnBrowse_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDataSource.Click, btnDatabaseName.Click
        Dim txt As TextBox = Nothing
        Select Case CType(sender, Control).Name
            Case btnDataSource.Name : txt = txtDataSource
            Case btnDatabaseName.Name : txt = txtDatabaseName
        End Select
        GetDatabase(txt)
        Select Case SelectedDatabaseType()
            Case clsDB.enumDBType.Access, clsDB.enumDBType.Firebird_Embedded, clsDB.enumDBType.SQLite, clsDB.enumDBType.SQL_Server_CE
                Project.SQLDir = IO.Path.GetDirectoryName(AbsolutePath(txtDataSource.Text))
        End Select
    End Sub

    Private Function SelectedDatabaseType() As clsDB.enumDBType
        Return [Enum].Parse(GetType(clsDB.enumDBType), cboDatabaseType.Text.Replace(" ", "_"))
    End Function

    Private Sub GetDatabase(ByRef txt As TextBox)
        Try
            Dim Ext, Filter As String

            If SelectedDatabaseType() = clsDB.enumDBType.Access Then
                Ext = ".mdb"
                Filter = "Microsoft Access Database (*.mdb)|*.mdb"
            ElseIf SelectedDatabaseType() = clsDB.enumDBType.SQL_Server_CE Then
                Ext = ".sdf"
                Filter = "SQL Server CE Database (*.sdf)|*.sdf"
            ElseIf SelectedDatabaseType() = clsDB.enumDBType.Firebird_Embedded Then
                Ext = ".fdb"
                Filter = "Firebird Database (*.fdb)|*.fdb"
            ElseIf SelectedDatabaseType() = clsDB.enumDBType.SQLite Then
                Ext = ".sdb"
                Filter = "SQLite 3 Database (*.sdb)|*.sdb"
            Else
                Ext = ""
                Filter = ""
            End If
            Filter &= "|All Files (*.*)|*.*"

            Select Case SelectedDatabaseType()
                Case clsDB.enumDBType.Access, clsDB.enumDBType.Firebird_Embedded, clsDB.enumDBType.SQLite, clsDB.enumDBType.SQL_Server_CE
                    With New OpenFileDialog
                        .AddExtension = True
                        .CheckPathExists = True
                        .CheckFileExists = False
                        .DefaultExt = Ext
                        .Filter = Filter

                        Dim InitDir As String = GetSetting(REGAPP, Me.Name, "DatabaseDir", MyDataPath)
                        If Not String.IsNullOrEmpty(txt.Text) Then InitDir = IO.Path.GetDirectoryName(AbsolutePath(txt.Text))
                        If IO.Directory.Exists(InitDir) Then
                            .InitialDirectory = InitDir
                        Else
                            .InitialDirectory = MyDataPath()
                            If Not My.Computer.FileSystem.DirectoryExists(.InitialDirectory) Then My.Computer.FileSystem.CreateDirectory(.InitialDirectory)
                        End If
                        If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                            txt.Text = RelativePath(.FileName)
                            SaveSetting(REGAPP, Me.Name, "DatabaseDir", IO.Path.GetDirectoryName(.FileName))
                        End If
                    End With
                Case clsDB.enumDBType.SQL_Server, clsDB.enumDBType.MySQL
                    Dim DatabaseList As New Generic.List(Of String)
                    With Project
                        .DB = clsDB.GetDataProvider(SelectedDatabaseType, Me.txtDataSource.Text, IIf(SelectedDatabaseType() = clsDB.enumDBType.SQL_Server, "master", "mysql"), txtUserName.Text, txtPswd.Text, txtTimeout.Text)
                        If .DB IsNot Nothing AndAlso .DB.OpenConnection Then
                            Dim dt As DataTable = .DB.Connection.GetSchema("DATABASES")
                            Dim found As Boolean = False
                            For Each dr As DataRow In dt.Rows
                                DatabaseList.Add(dr("Database_Name").ToString)
                            Next
                            DatabaseList.Sort()
                            dt.Dispose()
                            dt = Nothing
                            .DB.Connection.Close()
                            With New frmSelect(False)
                                .lstItems.Items.AddRange(DatabaseList.ToArray)
                                If .ShowDialog(Me) = Windows.Forms.DialogResult.OK Then
                                    txt.Text = .lstItems.Text
                                End If
                                .Dispose()
                            End With
                        End If
                    End With
                Case Else
                    lblInfo.Visible = True
                    tblConfig.Visible = False
                    Dim s As String = GetConnectString()
                    lblInfo.Visible = False
                    tblConfig.Visible = True

                    If s = "" Then Exit Sub

                    Dim ar() As String = s.Split(";")
                    Me.txtPswd.UseSystemPasswordChar = False
                    Me.txtPswd.PasswordChar = ""
                    Me.txtPswd.Text = "?Enter Password Here?"
                    For i As Int16 = 0 To UBound(ar)
                        If ar(i).StartsWith("DATA SOURCE", StringComparison.OrdinalIgnoreCase) Then
                            txtDataSource.Text = ar(i).Split("=")(1).Trim
                        ElseIf ar(i).StartsWith("INITIAL CATALOG", StringComparison.OrdinalIgnoreCase) Then
                            txtDatabaseName.Text = ar(i).Split("=")(1).Trim
                        ElseIf ar(i).StartsWith("USER ID", StringComparison.OrdinalIgnoreCase) Then
                            txtUserName.Text = ar(i).Split("=")(1).Trim
                        ElseIf ar(i).StartsWith("PASSWORD", StringComparison.OrdinalIgnoreCase) Then
                            txtPswd.Text = ar(i).Split("=")(1).Trim
                        End If
                    Next
            End Select
        Catch ex As Exception
            ErrorMsg(, ex)
        End Try
    End Sub

    Private Function GetConnectString() As String
        'Purpose of Function: Build a Connection String
        'References required: oledb32.dll (MS Ole DB Service component)
        'Returns a standard connection string
        Try
            Dim varDataLink As New MSDASC.DataLinks
            Dim oConn As Object = varDataLink.PromptNew()
            If oConn Is Nothing Then Return "" Else Return oConn.ConnectionString
        Catch ex As Exception
            ErrorMsg("Unable to build connection string.", ex)
            Return Nothing
        End Try
    End Function

    Private Sub frmPrefs_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        SaveWindowPos(REGAPP, Me)
    End Sub

    Private Sub frmPrefs_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        GetWindowPos(REGAPP, Me)
        ReplaceTooltipAndHelpText(Me, Me.ToolTip1, Me.HelpProvider1)
        If modWRDB.Project Is Nothing Then
            Project = New clsProject
        Else
            Project = modWRDB.Project.Clone
        End If
        LoadForm()
    End Sub

    Private Sub txt_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtDatabaseName.TextChanged, txtDataSource.TextChanged, txtUserName.TextChanged
        With CType(sender, TextBox)
            ToolTip1.SetToolTip(sender, .Text)
        End With
        DatabaseHasChanged = True
    End Sub

    Private Sub cboDatabaseType_SelectionChangeCommitted(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboDatabaseType.SelectionChangeCommitted
        Me.txtDatabaseName.Clear()
        Me.txtDataSource.Clear()
        Me.cboMasterTable.SelectedIndex = -1
        Me.txtPswd.Clear()
        Me.txtUserName.Clear()
    End Sub

    Private Sub txtDataSource_Validated(ByVal sender As Object, ByVal e As System.EventArgs) Handles txtDataSource.Validated
        Select Case SelectedDatabaseType()
            Case clsDB.enumDBType.Access, clsDB.enumDBType.Firebird_Embedded, clsDB.enumDBType.SQLite, clsDB.enumDBType.SQL_Server_CE
                Project.SQLDir = IO.Path.GetDirectoryName(AbsolutePath(txtDataSource.Text))
        End Select
    End Sub

    Private Sub cboMasterTable_DropDown(ByVal sender As Object, ByVal e As System.EventArgs) Handles cboMasterTable.DropDown
        cboMasterTable.Items.Clear()
        With Project
            If TestConnection() Then
                Dim MasterTableList As New Generic.List(Of String)
                For Each s As String In .GetTableList(clsProject.enumTableTypes.Working, clsProject.enumTableTypes.Master)
                    MasterTableList.Add(s)
                Next
                .DB.Connection.Close()
                Application.DoEvents()
                cboMasterTable.Items.AddRange(MasterTableList.ToArray)
                If MasterTableList.Count = 0 AndAlso MessageBox.Show("No data tables exist in this project; do you want to create a new Master table now?", "Select Master Table", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) = Windows.Forms.DialogResult.OK Then
                    btnCreateMaster.PerformClick()
                End If
            End If
        End With
    End Sub

    Private Sub lnkClearRecent_LinkClicked(sender As System.Object, e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles lnkClearRecent.LinkClicked
        With MainForm
            With .mruMenuProj
                .RemoveAll()
                .ClearRegistry()
            End With
            With .mruMenuTable
                .RemoveAll()
                .ClearRegistry()
            End With
        End With
        frmInfoMsg.ResetAllInfoMsgs()
    End Sub

    Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
        Close()
    End Sub

    Private Sub btnCreateMaster_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreateMaster.Click
        If Not (TestConnection() AndAlso HasTablePermissions(Project)) Then Exit Sub

        Dim Master As String
        With Project
            Do
                Master = InputBox("Enter the name of the new Master table you wish to create:", "Create Master Table", IIf(cboMasterTable.Text = "", "Master", cboMasterTable.Text))
                If Master.Trim = "" Then Exit Sub

                If .DB.TableViewExists(Master) Then
                    If WarningMsg("That table already exists; either select it from the drop-down line or specify a different name.", , , True) = Windows.Forms.DialogResult.Cancel Then Exit Sub
                Else
                    Exit Do
                End If
            Loop
            Try
                Master = .DB.GetValidTableName(Master) : If Master = "" Then Exit Sub
                .CreateTableTemplates()
                If .DB.CreateTable(Master, .dsWRDB.Tables(clsProject.enumTableTypes.Master)) Then
                    .MasterTableName = Master
                    cboMasterTable.Text = Master
                End If
            Catch ex As DbSqlException
                WarningMsg(ex.Message)
            End Try
        End With
    End Sub

    Private Sub btnHelp_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnHelp.Click
        ShowHelp(Me, "12")
    End Sub

    Private Sub txtProjectPassword_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles txtProjectPassword.Validating
        txtProjectPassword.Text = txtProjectPassword.Text.Trim
        If txtProjectPassword.Text <> "" Then
            With New frmLogin
                .lblInfo.Text = "Please reenter the password to confirm..."
                If .ShowDialog(Me) = DialogResult.OK Then
                    If String.Equals(Me.txtProjectPassword.Text.Trim, .txtPassword.Text.Trim, StringComparison.InvariantCultureIgnoreCase) Then
                        Project.Password = txtProjectPassword.Text
                        e.Cancel = False
                    Else
                        WarningMsg("The two passwords did not match!")
                        e.Cancel = True
                    End If
                Else
                    e.Cancel = True
                End If
            End With
        End If
    End Sub

    Private Sub frmPrefs_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
        Static AlreadyShown As Boolean = False
        If Not AlreadyShown Then frmInfoMsg.ShowInfoMsg("Project Preferences", "Project Preferences are used to indicate where database files are located and select a number of options that control the appearance and operation of WRDB.\n\nIf you want to provide a measure of security to your Project tables, enter a Project Password. This will require that you reenter the password to gain access to some potentially destructive features of WRDB. You can also set some preferences which will hide some advanced features and force the database to be read-only to non-Supervisor users.\n\nHint: to provide the highest security for password-protected data providers like Oracle and SQL Server, the Project Supervisor can configure the project, place the WRDB.ini file on a network share, and require that all users reference that file for data access. See the online help manual for more information.")
        AlreadyShown = True
    End Sub

    Private Sub chkWindowsSecurity_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkWindowsSecurity.CheckedChanged
        lblUserName.Visible = Not chkWindowsSecurity.Checked
        txtUserName.Visible = Not chkWindowsSecurity.Checked
        lblPswd.Visible = Not chkWindowsSecurity.Checked
        txtPswd.Visible = Not chkWindowsSecurity.Checked
        If chkWindowsSecurity.Checked Then
            txtUserName.Text = ""
            txtPswd.Text = ""
        End If
    End Sub

    Private Sub btnLogin_Click(sender As System.Object, e As System.EventArgs) Handles btnLogin.Click
        If SupervisorEnabled() Then
            tabMain.TabPages.Insert(0, tpProjOptions)
            tabMain.TabPages.Insert(0, tpDatabase)
            tabMain.SelectedIndex = 0
            btnLogin.Visible = False
        End If
    End Sub

    Private Sub tabMain_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles tabMain.SelectedIndexChanged
        If DatabaseHasChanged And tabMain.SelectedIndex = 1 Then
            If TestConnection() Then
                clsConnections.SetProjectInfo(Project)
                Project = New clsProject(Project.Name)
                LoadForm()
            End If
        End If
    End Sub

End Class
